/*
 * Copyright (c) 2006-2021, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2021-06-26     RT-Thread    first version
 * 2022-06-20     wyj           1.1.0增加修正温度为0时，采用外部温湿压传感器
 */

#include <stdio.h>
#include <rtthread.h>
#include <rtdevice.h>
#include <board.h>
#include <fal.h>
#include <easyflash.h>
#include <string.h>
// #include <cJSON.h>>

#include <GLOBAL/version.h>
#include <GLOBAL/code.h>
#include <NET/net.h>
#include <OTA/http_ota.h>
#include <MQTT/mqtt.h>
#include <HONEYWELL_PRES_SPI/pres.h>
#include <am2305/am2305.h>
#include <IO/io.h>
#include "display/display.h"
// #include <ulog.h>

#define LED0_PIN           GET_PIN(A, 4)
#define DBG_TAG "main"
#define DBG_LVL DBG_LOG
#include <rtdbg.h>

#define RT_APP_PART_ADDR 0x8020000

static int32_t press;
static int16_t temperature;
static int16_t humidity;
static uint8_t use_ex_env_sensor = 0;

static int ota_app_vtor_reconfig(void)
{
#define NVIC_VTOR_MASK   0x3FFFFF80
    /* Set the Vector Table base location by user application firmware definition */
    SCB->VTOR = RT_APP_PART_ADDR & NVIC_VTOR_MASK;

    return 0;
}
INIT_BOARD_EXPORT(ota_app_vtor_reconfig);

// 升级进度回调函数
static void HttpOtaProgressCallback(uint8_t per)
{
    char buf[100];
    snprintf(buf, sizeof(buf), "{\"aswcode\":\"%d\",\"aswmsg\":\"%d\"}", CODE_GET_UPGRADE_PERCENT, per);
    mqtt_publish(buf);
}

// 环境信息检测
static void upload_environment()
{
    char buf[100];
    if( use_ex_env_sensor == 0 )
    {
        temperature = 0;
        humidity = 0;
        press = 0;
    }
    get_environment_true_value(&temperature, &humidity, &press);
    LOG_I("============DISPLAY INFO=============");
    LOG_I("| press: %d.%d     \t\t|", (int32_t )(press / 1000), (int32_t )(press % 1000));
    LOG_I("| temperature: %d.%d \t|", (int16_t )(temperature / 10), (int16_t )(temperature % 10));
    LOG_I("| humidity: %d.%d  \t\t|", (uint16_t )(humidity / 10), (uint16_t )(humidity % 10));
    LOG_I("=====================================");
    snprintf(buf, sizeof(buf), "{\"aswcode\":\"%d\",\"aswmsg\":[\"%d.%d\",\"%d.%d\",\"%d.%d\"]}",
            CODE_GET_ENVIRONMENT_REQUEST, (int16_t) (press / 1000), (int16_t) (press % 1000),
            (int16_t) (temperature / 10), (int16_t) (temperature % 10), (uint16_t) (humidity / 10),
            (uint16_t) (humidity % 10));
    mqtt_publish(buf);
}

// io 端口检测上传回调
static void IoUploadCallback(struct io_status_s *io_status)
{
    char buf[100];
    LOG_I("================================================IO STATUS=========================================");
    LOG_I("| key0: %d, key1: %d, key2: %d, key3: %d, infrared: %d, door: %d, realy0: %d, realy1: %d, chain: %d \t|",
            io_status->key0, io_status->key1, io_status->key2, io_status->key3, io_status->infrared, io_status->door,
            io_status->relay0, io_status->relay1, io_status->chain);
    LOG_I("==================================================================================================");
    snprintf(buf, sizeof(buf),
            "{\"aswcode\":\"%d\",\"aswmsg\":[\"%d\",\"%d\",\"%d\",\"%d\",\"%d\",\"%d\",\"%d\",\"%d\",\"%d\"]}",
            CODE_GET_PIN, io_status->key0, io_status->key1, io_status->key2, io_status->key3, io_status->infrared,
            io_status->door, io_status->relay0, io_status->relay1, io_status->chain);
    mqtt_publish(buf);
}

static void get_factor()
{
    float temperature_factor = get_t_cal_f();
    float humidity_factor = get_h_cal_f();
    float press_factor = get_p_cal_f();
    char buf[200];
    snprintf(buf, sizeof(buf),
            "{\"aswcode\":\"%d\",\"aswmsg\":{\"temperature_factor\":\"%d.%d\",\"humidity_factor\":\"%d.%d\",\"press_factor\":\"%d.%d\"}}",
            CODE_GET_FACTOR, (int16_t) (temperature_factor), (int16_t) (temperature_factor * 10) % 10,
            (int16_t) (humidity_factor), (int16_t) (humidity_factor * 10) % 10, (uint16_t) (press_factor),
            (uint16_t) (press_factor * 1000) % 1000);
    mqtt_publish(buf);
}

static void set_factor(cJSON *msg)
{
    cJSON *item;
    item = cJSON_GetObjectItem(msg, "temperature_factor");
    float temperature_factor = atof(item->valuestring);
    item = cJSON_GetObjectItem(msg, "humidity_factor");
    float humidity_factor = atof(item->valuestring);
    item = cJSON_GetObjectItem(msg, "press_factor");
    float press_factor = atof(item->valuestring);

    set_t_cal_f(temperature_factor); // 设置温度
    set_h_cal_f(humidity_factor); // 设置湿度
    set_p_cal_f(press_factor); // 设置压力

    LOG_I("============Set Factor=============");
    LOG_D("temperature factor: %d.%d", (int )temperature_factor, (int )(temperature_factor * 10) % 10);
    LOG_D("humidity factor: %d.%d", (int )humidity_factor, (int )(humidity_factor * 10) % 10);
    LOG_D("press factor: %d.%d", (int )press_factor, (int )(press_factor * 1000) % 1000);
    LOG_I("===================================");

    char buf[100];
    snprintf(buf, sizeof(buf), "{\"aswcode\":\"%d\",\"aswmsg\":\"%d\"}", CODE_SET_FACTOR, 1);
    mqtt_publish(buf);
    // cJSON_Delete(item);
}

// 设置net
static void set_net(cJSON *msg)
{
    struct NetConfig cfg;
    cJSON *item;
    item = cJSON_GetObjectItem(msg, "type");
    snprintf(cfg.NET_TYPE, sizeof(cfg.NET_TYPE), "%s", item->valuestring);
    item = cJSON_GetObjectItem(msg, "wifi_ssid");
    snprintf(cfg.NET_WIFI_SSID, sizeof(cfg.NET_WIFI_SSID), "%s", item->valuestring);
    item = cJSON_GetObjectItem(msg, "wifi_pwd");
    snprintf(cfg.NET_WIFI_PWD, sizeof(cfg.NET_WIFI_PWD), "%s", item->valuestring);
    item = cJSON_GetObjectItem(msg, "eth_mac");
    snprintf(cfg.NET_ETH_MAC, sizeof(cfg.NET_ETH_MAC), "%s", item->valuestring);
    LOG_I("===================Net SET CONFIG=================");
    LOG_I("| NET_TYPE\t| %s\t|", cfg.NET_TYPE);
    LOG_I("| NET_WIFI_SSID\t| %s\t|", cfg.NET_WIFI_SSID);
    LOG_I("| NET_WIFI_PWD\t| %s\t\t\t|", cfg.NET_WIFI_PWD);
    LOG_I("| NET_ETH_MAC\t| %s\t\t\t\t|", cfg.NET_ETH_MAC);
    LOG_I("==================================================");
    net_set_conf(cfg);
    char buf[100];
    snprintf(buf, sizeof(buf), "{\"aswcode\":\"%d\",\"aswmsg\":\"%d\"}", CODE_SET_NET, 1);
    mqtt_publish(buf);
}

// 获取net
static void get_net()
{
    struct NetConfig cfg;
    cfg = net_get_conf();
    LOG_I("===================Net GET CONFIG=================");
    LOG_I("| NET_TYPE\t| %s\t|", cfg.NET_TYPE);
    LOG_I("| NET_WIFI_SSID\t| %s\t|", cfg.NET_WIFI_SSID);
    LOG_I("| NET_WIFI_PWD\t| %s\t\t\t|", cfg.NET_WIFI_PWD);
    LOG_I("| NET_ETH_MAC\t| %s\t\t\t\t|", cfg.NET_ETH_MAC);
    LOG_I("==================================================");

    char buf[300];
    snprintf(buf, sizeof(buf),
            "{\"aswcode\":\"%d\",\"aswmsg\":{\"type\":\"%s\",\"wifi_ssid\":\"%s\",\"wifi_pwd\":\"%s\",\"eth_mac\":\"%s\"}}",
            CODE_GET_NET, cfg.NET_TYPE, cfg.NET_WIFI_SSID, cfg.NET_WIFI_PWD, cfg.NET_ETH_MAC);
    mqtt_publish(buf);
}

// 设置mqtt
static void set_mqtt(cJSON *msg)
{
    struct MQTTConfig mqtt_cfg;
    cJSON *item;
    item = cJSON_GetObjectItem(msg, "uri");
    snprintf(mqtt_cfg.MQTT_URI, sizeof(mqtt_cfg.MQTT_URI), "%s", item->valuestring);
    item = cJSON_GetObjectItem(msg, "clientid");
    snprintf(mqtt_cfg.MQTT_CLIENTID, sizeof(mqtt_cfg.MQTT_CLIENTID), "%s", item->valuestring);
    item = cJSON_GetObjectItem(msg, "username");
    snprintf(mqtt_cfg.MQTT_USERNAME, sizeof(mqtt_cfg.MQTT_USERNAME), "%s", item->valuestring);
    item = cJSON_GetObjectItem(msg, "password");
    snprintf(mqtt_cfg.MQTT_PASSWORD, sizeof(mqtt_cfg.MQTT_PASSWORD), "%s", item->valuestring);
    item = cJSON_GetObjectItem(msg, "subtopic");
    snprintf(mqtt_cfg.MQTT_SUBTOPIC, sizeof(mqtt_cfg.MQTT_SUBTOPIC), "%s", item->valuestring);
    item = cJSON_GetObjectItem(msg, "pubtopic");
    snprintf(mqtt_cfg.MQTT_PUBTOPIC, sizeof(mqtt_cfg.MQTT_PUBTOPIC), "%s", item->valuestring);
    item = cJSON_GetObjectItem(msg, "willmsg");
    snprintf(mqtt_cfg.MQTT_WILLMSG, sizeof(mqtt_cfg.MQTT_WILLMSG), "%s", item->valuestring);
    LOG_I("===================MQTT SET CONFIG================");
    LOG_I("| MQTT_URI\t| %s\t|", mqtt_cfg.MQTT_URI);
    LOG_I("| MQTT_CLIENTID\t| %s\t\t\t|", mqtt_cfg.MQTT_CLIENTID);
    LOG_I("| MQTT_USERNAME\t| %s\t\t\t\t|", mqtt_cfg.MQTT_USERNAME);
    LOG_I("| MQTT_PASSWORD\t| %s\t\t\t|", mqtt_cfg.MQTT_PASSWORD);
    LOG_I("| MQTT_SUBTOPIC\t| %s\t|", mqtt_cfg.MQTT_SUBTOPIC);
    LOG_I("| MQTT_PUBTOPIC\t| %s\t|", mqtt_cfg.MQTT_PUBTOPIC);
    LOG_I("| MQTT_WILLMSG\t| %s\t\t\t|", mqtt_cfg.MQTT_WILLMSG);
    LOG_I("==================================================");
    mqtt_set_conf(mqtt_cfg);

    char buf[100];
    snprintf(buf, sizeof(buf), "{\"aswcode\":\"%d\",\"aswmsg\":\"%d\"}", CODE_SET_MQTT, 1);
    mqtt_publish(buf);
}

// 获取mqtt
static void get_mqtt()
{
    struct MQTTConfig mqtt_cfg;
    mqtt_cfg = mqtt_get_conf();
    LOG_I("===================MQTT GET CONFIG====================");
    LOG_I("| MQTT_URI\t| %s\t|", mqtt_cfg.MQTT_URI);
    LOG_I("| MQTT_CLIENTID\t| %s\t\t\t|", mqtt_cfg.MQTT_CLIENTID);
    LOG_I("| MQTT_USERNAME\t| %s\t\t\t\t|", mqtt_cfg.MQTT_USERNAME);
    LOG_I("| MQTT_PASSWORD\t| %s\t\t\t|", mqtt_cfg.MQTT_PASSWORD);
    LOG_I("| MQTT_SUBTOPIC\t| %s\t|", mqtt_cfg.MQTT_SUBTOPIC);
    LOG_I("| MQTT_PUBTOPIC\t| %s\t|", mqtt_cfg.MQTT_PUBTOPIC);
    LOG_I("| MQTT_WILLMSG\t| %s\t\t\t|", mqtt_cfg.MQTT_WILLMSG);
    LOG_I("==================================================");

    char buf[300];
    snprintf(buf, sizeof(buf),
            "{\"aswcode\":\"%d\",\"aswmsg\":{\"uri\":\"%s\",\"clientid\":\"%s\",\"username\":\"%s\",\"password\":\"%s\",\"subtopic\":\"%s\",\"pubtopic\":\"%s\",\"willmsg\":\"%s\"}}",
            CODE_GET_MQTT, mqtt_cfg.MQTT_URI, mqtt_cfg.MQTT_CLIENTID, mqtt_cfg.MQTT_USERNAME, mqtt_cfg.MQTT_PASSWORD,
            mqtt_cfg.MQTT_SUBTOPIC, mqtt_cfg.MQTT_PUBTOPIC, mqtt_cfg.MQTT_WILLMSG);
    mqtt_publish(buf);
}

// mqtt信息处理
static void MqttRecvCallback(cJSON *code, cJSON *msg)
{
    // LOG_D("code:%s, msg: %s", code->valuestring, cJSON_Print(msg));
    LOG_D("===========mqtt_recv_callback============");
    int c = atoi(code->valuestring);
    LOG_D("GET GODE -> %d", c);
    switch (c)
    {
    case CODE_SET_RESET: // 设置->重启
        __set_FAULTMASK(1); //关闭总中断
        NVIC_SystemReset(); //请求单片机重启
        break;
    case CODE_GET_VERSION: // 获取->版本
        mqtt_send_msg(CODE_GET_VERSION, VERSION);
        break;
    case CODE_SET_VERSION: // 设置->版本
        break;
    case CODE_SET_UPGRADE: // 设置->升级
        mqtt_send_msg(CODE_SET_UPGRADE, "1");
        http_ota_start(msg->valuestring);
        break;
    case CODE_SET_NET: // 设置mqtt
        set_net(msg);
        break;
    case CODE_GET_NET: // 读取mqtt
        get_net();
        break;
    case CODE_SET_MQTT: // 设置mqtt
        set_mqtt(msg);
        break;
    case CODE_GET_MQTT: // 读取mqtt
        get_mqtt();
        break;
    case CODE_GET_ENVIRONMENT_REQUEST:          //上位机获取环境参数
        upload_environment();
    case CODE_GET_ENVIRONMENT:
        if (msg != NULL)
        {
            int array_size = cJSON_GetArraySize(msg);
            if( array_size == 3 )
            {
                LOG_I("got 3 extern environment data!");
                char *env_data[3];
                for( int i = 0;i<3;i++)
                {
                    cJSON * pSub = cJSON_GetArrayItem(msg, i);
                    if(pSub != NULL)
                    {
                        env_data[i] = pSub->valuestring ;
                        LOG_D("env[%d] : %s",i,env_data[i]);
                    }
                }

                use_ex_env_sensor = 1;
                press = atof(env_data[0])*1000;
                temperature = atof(env_data[1])*100;
                humidity = atof(env_data[2])*10;

                LOG_D("extern sensor data,P:[%d.%d],T:[%d.%d],H:[[%d.%d]]",
                        (int16_t) (press / 1000), (int16_t) (press % 1000),
                        (int16_t) (temperature / 10), (int16_t) (temperature % 10),
                        (uint16_t) (humidity / 10),(uint16_t) (humidity % 10));

            }
            else {
                LOG_I("got extern environment data num error!");
            }
        }

    case CODE_GET_PIN:
        io_check_once();
        break;
    case CODE_SET_AUTO:
        mqtt_send_msg(CODE_SET_AUTO, "1");
        break;
    case CODE_GET_FACTOR: // 获取刻度因子
        get_factor();
        break;
    case CODE_SET_FACTOR: // 设置刻度因子
        set_factor(msg);
        break;

    default:
        break;
    }
}

int main(void)
{
    int count = 1;
    int led_status = 0;
    int net_flag = 1; // 开启网络检测
    int mqtt_flag = 1; // mqtt连接成功初始化
    int delay_cnt = 0; // 延时发送

    rt_pin_mode(LED0_PIN, PIN_MODE_OUTPUT);

    LOG_I("*******************************\r\n");
    LOG_I("app version:%s\r\n", VERSION);
    LOG_I("*******************************\r\n");

    // 升级回调函数
    http_ota_progress_callback = HttpOtaProgressCallback;
    // mqtt接收信息回调函数
    mqtt_recv_callback = MqttRecvCallback;
    // 硬件io检测
    io_upload_callback = IoUploadCallback;

    fal_init();
    easyflash_init();

    // IO引脚初始化
    io_init();
    io_check_start(); // 开启io连锁检查
    display_init(); // 显示初始化
    // 设置
    net_init();

    while (1)
    {
        count++;
        // 10秒 上传温湿度
        if (count % 100 == 0)
        {
            upload_environment();
        }
        // 1秒, 系统指示灯周期性闪烁
        if (count % 10 == 0)
        {
            led_status++;
            rt_pin_write(LED0_PIN, led_status % 2);
            if (net_flag)
            {
                if (net_is_connected())
                {
                    net_flag = 0;
                    mqtt_start();
                }
            }
            // mqtt连接成功，初始化发送相关信息
            if (mqtt_flag)
            {
                if (mqtt_is_connected())
                {
                    if (delay_cnt == 2)
                    {
                        mqtt_send_msg(CODE_GET_VERSION, VERSION); // 发送版本号
                    }
                    if (delay_cnt == 3)
                    {
                        // 开启io检测
                        mqtt_flag = 0; // 关闭
                    }
                    delay_cnt++;
                }
            }
        }
        rt_thread_mdelay(100);
    }

    return RT_EOK;
}
